import React, { useEffect, useState } from 'react';
import { useAppSelector } from '../../redux/hooks';
import TutorialBubble from './TutorialBubble';

interface TutorialStep {
  target: string;
  validation?: string;
  title: string;
  content: React.ReactNode;
  waitFor?: string;
  grabGlobalClick?: boolean;
  collectionIndex?: number;
}

interface TutorialObserverProps {
  steps: TutorialStep[];
  tourStep: number;
  requestedTourStep: number | null;
  startTutorialStep: () => void;
  stopTutorialStep: () => void;
  incrementTutorialStep: () => void;
  validateTutorialStep: (e: { tourStep: number }) => void;
  checkBubbleRender: (e: any) => void;
  lastCheckRender: any;
  children?: React.ReactNode;
}

/**
 * TutorialObserver Component
 * Observes DOM changes and displays tutorial bubbles
 */
const TutorialObserver: React.FC<TutorialObserverProps> = (props) => {
  const tourRunning = useAppSelector((state) => state.tutorial.tourRunning);
  const [observer, setObserver] = useState<MutationObserver | null>(null);

  const {
    steps,
    tourStep,
    requestedTourStep,
    startTutorialStep,
    stopTutorialStep,
    incrementTutorialStep,
    validateTutorialStep,
    checkBubbleRender,
    lastCheckRender,
    children,
  } = props;

  const bubbleUpdate = (): void => {
    checkBubbleRender({ epoch: Date.now() });
  };

  useEffect(() => {
    if (!tourRunning) {
      // Stop observing the DOM when the tutorial is finished
      observer?.disconnect();
      return;
    }
    // Listen for new components being added to the DOM
    const obs = new MutationObserver((mutationsList) => {
      if (mutationsList.length > 0) {
        bubbleUpdate();
      }
    });

    // Start observing the DOM
    obs.observe(document.body, { childList: true, subtree: true, attributes: true });
    setObserver(obs);

    return () => {
      obs.disconnect();
    };
  }, [tourRunning]);

  const startTutorialCallBack = (): void => {
    startTutorialStep();
  };

  const stopTutorial = (): void => {
    stopTutorialStep();
  };

  const doIncrementTutorialStep = (): void => {
    if (requestedTourStep !== null) {
      validateTutorialStep({ tourStep: requestedTourStep });
    }
    incrementTutorialStep();
  };

  return (
    <>
      {children}
      {tourRunning && (
        <TutorialBubble
          requestedTourStep={requestedTourStep}
          currentTourStep={tourStep}
          steps={steps}
          stopTutorial={stopTutorial}
          incrementTutorialStep={doIncrementTutorialStep}
          validateTutorialStep={validateTutorialStep}
          lastCheckRender={lastCheckRender}
        />
      )}
    </>
  );
};

export default TutorialObserver;

